#include "EndConnectInsDestHandler.h"
#include "BeginConnectOriDestHandler.h"
#include "EndInsDestSendHandler.h"
#include "StringHelper.h"
#include "Log.h"
#include "GlobalContext.h"
#include "CookieHelper.h"

using namespace std;
using namespace log4cplus;

Logger EndConnectInsDestHandler::log=GetLogger(LOG4CPLUS_TEXT("EndConnectInsDestHandler"));

void EndConnectInsDestHandler::GetSendInfo(ClientContext &client,SOCKET *sendSock,OVERLAPPED **sendOvl)
{
	*sendSock=client.InsteadContext().TempSock();
	*sendOvl=client.InsteadContext().TempOVL();
	LOG4CPLUS_DEBUG_STR(log,LOG4CPLUS_TEXT("Set http request data(instead server) send info."));
}

ITransHandler* EndConnectInsDestHandler::GetNextHandler()
{
	return new EndInsDestSendHandler();
}

ITransHandler::ExecuteResultCode EndConnectInsDestHandler::OnExecuteError(ClientContext &client,OVERLAPPED *ovl,ITransHandler::ExecuteResultCode executeResult)
{
	delete client.SetCurrentHandler(new BeginConnectOriDestHandler());
	client.FreeInsteadContext();
	LOG4CPLUS_DEBUG_STR(log,LOG4CPLUS_TEXT("Try to send instead server request data failed(free instead context),try to connect original server."));
	::PostQueuedCompletionStatus(GlobalContext::Instance().IOCP(),0,static_cast<ULONG_PTR>(client.SequenceNo()),ovl);
	return ITransHandler::ExecuteOK;
}

string* EndConnectInsDestHandler::AssemblyHttpRequest(ClientContext &client)
{
	HttpRequestPack &request=client.HttpRequest();
	string *requestStr=new string();
	string str=StringHelper::ToString(m_insteadUrl.ServerPort());
	requestStr->append("GET ");
	requestStr->append(m_insteadUrl.Path());
	requestStr->append(" ");
	requestStr->append(request.Version());
	requestStr->append("\r\n");

	requestStr->append("Host: ");
	requestStr->append(m_insteadUrl.ServerName());
	/*requestStr->append(":");
	requestStr->append(str);*/
	requestStr->append("\r\n");

	requestStr->append("Cache-Control: max-age=0\r\n");
	requestStr->append("User-Agent: PS3TransAgent\r\n");
	requestStr->append("Accept: */*\r\n");
	requestStr->append("Accept-Encoding: identity\r\n");
	requestStr->append("Pragma: no-cache\r\n");
	requestStr->append("Range: bytes=");
	requestStr->append(StringHelper::ToString(client.TranslatedFileIndex()));
	requestStr->append("-");
	if(client.MaxFileIndex()!=UNINITIALIZE_FILE_SIZE_INDEX)
	{
		requestStr->append(StringHelper::ToString(client.MaxFileIndex()));
	}
	requestStr->append("\r\n");

	string url;
	url.append("http://");
	url.append(m_insteadUrl.ServerName());
	if(m_insteadUrl.ServerPort()!=80)
	{
		url.append(":");
		url.append(str);
	}
	url.append(m_insteadUrl.Path());
	char *cookie=GetCookie(url);
	if(cookie!=NULL)
	{
		try
		{
			requestStr->append("Cookie: ");
			requestStr->append(cookie);
			requestStr->append("\r\n");
			delete []cookie;
		}
		catch(...)
		{
			if(cookie!=NULL)
			{
				delete []cookie;
				LOG4CPLUS_ERROR_STR(log,LOG4CPLUS_TEXT("Append instead server cookie catch an exception."));
			}
		}
	}
	else
	{
		LOG4CPLUS_ERROR_STR(log,LOG4CPLUS_TEXT("Get instead server cookie failed."));
	}

	requestStr->append("Connection: close\r\n");
	requestStr->append("\r\n");
	return requestStr;
}

WSABUF* EndConnectInsDestHandler::FillBufferWithHttpRequest(ClientContext &client,std::string *requestStr)
{
	client.InsteadContext().SetTempRequestBuffer(requestStr);

	if(requestStr->size()>client.InsteadContext().TempBuffer()->len)
	{
		memcpy_s(client.InsteadContext().TempBuffer()->buf,client.InsteadContext().TempBuffer()->len,requestStr->c_str(),client.InsteadContext().TempBuffer()->len);
		client.InsteadContext().TempWeakRefBuffer()->buf=client.InsteadContext().TempBuffer()->buf;
		client.InsteadContext().TempWeakRefBuffer()->len=client.InsteadContext().TempBuffer()->len;
		client.InsteadContext().SetPartialTransIndex(client.InsteadContext().TempBuffer()->len);
	}
	else
	{
		memcpy_s(client.InsteadContext().TempBuffer()->buf,client.InsteadContext().TempBuffer()->len,requestStr->c_str(),requestStr->size());
		client.InsteadContext().TempWeakRefBuffer()->buf=client.InsteadContext().TempBuffer()->buf;
		client.InsteadContext().TempWeakRefBuffer()->len=requestStr->size();
		client.InsteadContext().SetPartialTransIndex(0);
	}
	return client.InsteadContext().TempWeakRefBuffer();
}

char* EndConnectInsDestHandler::GetCookie(const string &url)
{
	wstring *wUrl=StringHelper::MultiByteToUnicode(url);
	char *ret=NULL;
	if(wUrl!=NULL)
	{
		wchar_t *wCookie=CookieHelper::GetAllCookies(*wUrl);
		delete wUrl;
		if(wCookie!=NULL)
		{
			ret = StringHelper::UnicodeToMultiByte(wCookie);
			delete []wCookie;
		}
	}
	return ret;
}